Chapter 2. Advanced Introduction to JavaScript

This chapter is dedicated to the JavaScript programming language. Our challenging goal is “From Zero to Hero in 50 pages”. While in the future chapters you’ll see how JavaScript frameworks can greatly minimize the amount of the JavaScript code that you need to write manually, you still need to understand the language itself.

This chapter starts with basics of the language, but then it quickly progresses to such advanced topics as prototypal inheritance, callbacks, and closures. If you prefer more fundamental and detail-oriented way of learning programming languages, read the book “Modern JavaScript. Develop and Design” by Larry Ullman or “JavaScript: The Definite Guide”, Sixth Edition by David Flanagan.

Besides the JavaScript coverage this chapter includes a section on the tools (IDEs, debuggers, Web inspectors et al.) that will make your development process more productive. In Chapter 3 we’ll start working on the first implementation of the Web site "Save Sick Child", which will include some JavaScript code.

JavaScript: A Brief History

The JavaScript programming language was designed in 1995 by Brendan Eich, who was working for Netscape Communication Corporation at the time. His goal was to allow developers create more interactive Web pages. Initially the name of this language was Mocha, then LiveScript, and finally Netscape agreed with Sun Microsystems, creator of Java (another new at the time language) to rename it to JavaScript.

A year later, the language was given to an international standards body called ECMA, which formalized the language into ECMAScript standard so that other browser vendors could create their implementation of this standard. ActionScript is a good example of another popular dialect of ECMAScript.

To learn more about the history of JavaScript from the source watch the Brendan Eich’s presentation “JavaScript at 17” at O’Reilly’s conference Fluent 2012.

Although the vast majority of today’s JavaScript code is being executed by the Web browsers some third-party tools also include JavaScript engines. For example, Google’s V8 JavaScript engine is used not only in the Chrome browser, but it’s a server-side way to run the code written in JavaScript framework node.js. Using the same programming language on the client and the server is the main selling point of node.js. Oracle’s Java Development Kit (JDK) 8 includes the JavaScript engine Nashorn that can run on both the server and the client computers.

In the 90th, JavaScript was considered a second class language used mainly for prettifying Web pages. In the beginning of the 21st Century the techniques known as AJAX (described in Chapter 4) made a significant impact to the way Web pages were built. With AJAX, the specific content inside the Web page could be updated without the need to make a full page refresh. Think of Google’s gmail that inserts just one line at the top of your input box when new email arrives - it doesn’t re-retrieve the entire content of your inbox from the server.

AJAX gave a second birth to JavaScript. But the vendors of Web browsers were no eager to implement the latest specifications of ECMAScript. Browsers’ incompatibility and lack of good development tools prevented JavaScript to become the language of choice for Web applications. Let’s not forget about the ubiquitous Flash Player – an excellent VM supported by all Web browsers. Rich Internet Applications written in ActionScript were compiled into the byte code and executed by Flash Player on the user’s machine inside the Web browser.

If AJAX saved JavaScript, then rapid proliferation of tablets and smartphones made it really hot. Today’s mobile devices come equipped with modern Web browsers and in the mobile world there is no need to make sure that your Web application will work in the 12 year old Internet Explorer 6. Adobe’s decision to stop supporting Flash Player in the mobile Web browsers is yet another reason to turn to JavaScript if your Web application has to be accessed from smartphones or tablets. The ECMASript, 5th Edition has been published in 2009 and is currently supported by all modern Web browsers. If you are interested in discovering if specific features of ECMAScript 5 are supported by a particular Web browser, check the latest version of the ECMAScript 5 compatibility table. At the time of this writing the snapshot of the Chrome Browser v. 22 looks as in Figure 2-1 below:

image

Figure 2-1. ECMAScript 5 Compatibility Sample Chart

JavaScript became the lowest common denominator available on thousands of different devices. Yes, the JavaScript engines are not exactly the same on thousands devices that people use to login to Facebook, but they are pretty close, and using some of the JavaScript frameworks spare you from worrying about their incompatibilities.

JavaScript is an interpreted language that arrives to the place of execution as text. The JavaScript engine optimizes and compiles the code before the execution. If the JavaScript engine is a part of a Web page, the browser will load and execute the JavaScript code embedded or referenced between the HTML tags <script> and </script>. JavaScript was originally created for Web browsers, which were supposed to display whatever content has successfully arrived. What if an image has not arrived from the server? You’ll see a broken image icon. What if not all JavaScript code has arrived to the browser? Well, the engine will try to execute whatever is available. The end users may appreciate such browser’s forgiveness when at least some content is available, but the software developers should be ready to spend more time debugging (in multiple browsers) the errors that could have been caught by compilers in other programming languages.

Why Declaring JavaScript Variables

JavaScript is a weakly typed language hence the developers don’t have a luxury of strong compiler’s help that Java or C# developers enjoy. This is easily explainable. Imagine that if in Java or C# instead of declaring variables of specific data types everything would be of type Object, and you could assign to it any value – a string, a number, or a custom object Person. This would substantially complicate the ability of the compiler to weed out all possible errors. You don’t need to declare variables in JavaScript – just assign a value and the JavaScript engine will figure out the proper type during the execution of your code.For example, the variable named girlfriend will have a data type of String:

girlfriendName=“Mary”;

Since I haven’t used the keyword var in front of girlfriend, this variable will have the global scope. Variables declared with var inside functions are local. Consider the following function declaration:

function addPersonalInfo(){
   var address ="123 Main Street";      // local String variable
   age=25;                              // global Number variable
   var isMarried = true;                // local boolean variable
       isMarried = "don't remember";    // now it's of String type
}

The variables address and isMarried are visible only inside the function addPersonalInfo(). The variable age becomes global because of omission of the keyword var. In Chapter 3, you’ll see an example of how to limit the scope of the variables to avoid polluting the global name space.

The variable isMarried changes its type from Boolean to String during the execution of the above script, and JavaScript engine won’t complain assuming that the programmer knows what she’s doing. So be ready for the run-time surprises and allocate a lot more time for testing than in case of compiled languages.

Yet another moving part is the JavaScript engine where your code will run. Unless you are developing for strictly controlled enterprise environment you can’t assume that the end-user will have the same runtime as yours. This is yet another reason to test your code in multiple Web browsers.

Which IDE to Use

Selecting an Integrated Development Environment (IDE) that supports JavaScript is a matter of your personal preference. Since there is no compilation stage and most of your debugging will be done using the Web browser tools, picking a text editor that supports syntax highlighting is all that most developers need. For example, there is an excellent commercial text editor Sublime Text 2. Among many programming languages this editor understands the keywords of HTML, CSS, and JavaScript, and it offers not only syntax highlighting, context sensitive help, and auto-complete too.

If you are coming from the Java background, the chances are that you are familiar with free and open sourced Eclipse IDE. In this case install the Eclipse plugin VJET by eBay.

Oracle’s IDE NetBeans 7.3 and above support HTML5 and JavaScript development and includes JavaScript debugger that allows your code to connect to the Web browser, but you are debugging inside the IDE. If you prefer Microsoft technologies, they offer excellent JavaScript support in Visual Studio 2012.

In this book we’ll use an Eclipse-based Aptana Studio 3 IDE. Aptana Studio is available free of charge. Aptana Studio comes with embedded Web Server so you can test your JavaScript code without the need to start any additional software. In this chapter we’ll use Aptana Studio IDE to illustrate the features of JavaScript, and in the next chapter you’ll be working with a number of Aptana projects that will lead you through the development of the first version of our Save Sick Child Web application.

For the real world development we recommend using a commercial IDE WebStorm from JetBrains. In addition to smart context sensitive help, auto-complete, and syntax highlighting it offers HTML5 templates, a code coverage feature for unit testing that identifies the code fragment that haven’t been tested. All of the editors and IDEs listed here are either available for free or are priced in the area of $60 USD. Try them all and pick the one that best fits your coding habits.

Getting Familiar with Aptana IDE

Download and install Aptana Studio 3 from http://aptana.com. Start Aptana and close the start page it displays by clicking on the little X on the tab. Then customize the color theme of this IDE by clicking the rainbow-colored circle on its toolbar. We usually select the theme called Eclipse. After the first start of Aptana you’ll see the message on the left side that reads “There are no projects in your workspace. To get started, please create or import an existing one.”

If you want to start playing with the code samples that come with this book, click on the button Import Project, select the General | Archive file. Find the zip file you’d like to use, e.g. chapter2.zip, and press Finish. The project from the selected zip file will be imported into the Aptana’s workspace, which is nothing more than a folder on the disk where the source code will reside. When you work in Aptana IDE you see a set of views (panels). This set is called perspective. For Web projects Aptana uses Web perspective, which is indicated at the top right corner. Pressing the icon with a little pus sign at the top right allows to open another perspective with its own set of views.

Let’s get started with creating a project from scratch by pressing the button Create Project on the left. You could have also created a new Web Project using the File menu. On the next window you’ll need to select a wizard, and we’ll be always working with Web Projects throughout this book. The next window will offer you to select a project template - let’s stick to the simplest one - Default Project. Name it MyFirstProject.

To add an HTML file to this project select the menu File | New From Template | HTML | HTML5 Template. Aptana will offer you new_file.html the name of this file - no need to change it for now. Just press finish and you’ll see a window similar to the one shown on Figure 2-2.

image

Figure 2-2. Aptana IDE with one HTML5 file

Right-click on the new_file.html and select the menu Run as JavaScript Web project. Don’t get upset that there is no JavaScript code there yet - we’ll add it pretty soon. Aptana starts its built-in Web server that by default runs on the port 8020 (it’s configurable in Aptana Preferences). The Web browser opens up and displays the page that looks like the one in Figure 2-3. Aptana has used its default template to generate HTML file. The template can be changed to your liking, and you can read about it in Aptana’s documentation at http://bitly.com/LRqRdU.

image

Figure 2-2. Running MyFirstProject

Tip
To configure the Web Browser that Aptana should open by default, open its Preferences window and select the Web browser of your choice under the General section. Many examples in this chapter use the Firefox with installed add-on Firebug, so start with making Firefox your default browser.

Adding JavaScript to HTML

If your JavaScript is a part of HTML document, typically, you’ll be adding your <script> tags at the end of HTML file. The reason is simple - your JavaScript code may be manipulating with HTML elements, and you want them to exist by the time the script runs. The other way to ensure that the code is not running unless the Web page has loaded is by catching window’s load event, and you’ll see such example later in this chapter in the section on browser’s events. Some JavaScript frameworks may have their own approach to dealing with HTML content and in Chapter 7 you’ll see that the main HTML file of the Web application written with Ext JS framework has <script> tags followed by the empty <body> tags. But let’s keep things simple for now.

Add the following fragment at the very end (right above the closing </body> tag) of the new_file.html from Figure 2-2.

<script>
   alert("Hello from JavaScript");
</script>

Run the new_file.html in Aptana and you’ll see the following output in your Web browser:

image

Figure 2-4. Running MyFirstProject with JavaScript at the bottom

Note that the Alert popup box is shown on top of the Web page that already rendered all of its HTML components. Now move the above code up to the end of the <head> section and re-run new_file.html. The picture is different now - the Alert box is shown before the HTML rendering is complete.

image

Figure 2-5. Running MyFirstProject with JavaScript at the top

In this simple example this doesn’t cause any malfunctioning of the code, but if our JavaScript would need to manipulate with HTML elements, we’d run into issues of accessing non-existent components.

Tip
Beside simple Alert box, JavaScript has Confirm and Prompt boxes, which allow asking OK/Cancel type of questions or require some input from the user.

Debugging JavaScript in Web Browsers

The best way to learn any program is to run it step by step through a debugger. While some people appreciate using debuggers offered by Aptana, NetBeans, or Visual Studio, we prefer to debug using great tools offered by the Web browsers. Here’s what you’ve got:

  • Firefox: FireBug add-on

  • Chrome: Developer Tools

  • Internet Explorer: F12 Developer Tools

  • Safari: the menu Develop

  • Opera Dragonfly

We’ll be doing most of the debugging in FireBug or Chrome Developer Tools. Both of them provide valuable information about your code and are easy to use. To get FireBug go to www.getfirebug.com and press the red button Install Firebug and follow the instructions. In Firefox, open the Firebug panel from the menu View.

image

Figure 2-6. FireBug Console

Select the Console option on the Firebug toolbar and enter alert("Hello from JavaScript") after the >>> sign and you’ll see the Alert box. To enter multi-line JavaScript code press the little circle with a caret at the bottom right corner and FireBug will open a panel on the right, where you can enter and run your JavaScript code.

This was probably the last example where we used the Alert() popup box for debugging purposes. All JavaScript debuggers support the console.log() for printing debug information. Consider the following example that illustrate strict equality operator ===. Yes, it’s three equal signs in a row. This operator evaluates to true if the values are equal and the data types are the same.

var age=25;

var ageStr="25";

if (age==ageStr){
  console.log("The values of age and ageStr are equal");
}

if (age===ageStr){
 console.log("The values of age and ageStr are strictly equal");
} else{
 console.log ("The values of age and ageStr are not strictly equal");
}

Running this code in the FireBug console produces the following output:

image

Figure 2-7. Using console.log() for the debug output

Tip
You can also use console.info(), console.debug(), and console.error() so debuggers may highlight the output with different colors or mark with different icons.
Tip
For more information about debugging JavaScript refer to the code samples illustrated in Figure 2-8 and 2-9.

JavaScript Functions. Gentle Introduction

Now comes the chicken or the egg dilemma. What should we explain first - functions or objects? Understanding of objects is needed for some of the function code samples and visa versa. We’ll start with simple function use cases, but will be switching to objects as needed.

Many of the readers can have experience with object-oriented languages like Java or C#, where classes can include methods implementing required functionality. Then these methods can be invoked with or without instantiation of the objects. If a JavaScript object includes functions they are called methods. But JavaScript functions don’t have to belong to an object. You can just declare a function and invoke it. Just like this:

//Function declaration
function calcTax (income, dependents){
   var tax;
   // Do stuff here
   return tax;
}

//Function invocation
calcTax(50000, 2);
var myTax = calcTax(50000,2);

Please note that the data types of the function parameters income and dependents are not specified. We can only guess that they are numbers based on their names. If a software developer won’t bother giving meaningful names to function parameters, the code becomes difficult to read. After the function calcTax() is invoked and complete, the variable myTax will have the value returned by the function. In the above code sample the JavaScript engine will not evaluate the function calcTax() until it’s actually invoked.

Another important thing to notice is that our function has a name calcTax. But this is not always the case - JavaScript allows functions to be anonymous. If you see the line of code where the keyword function is preceded by any other character this is not a function declaration, but a function expression. Consider the following variation of the tax calculation sample:

//Function expression
var doTax=function (income, dependents){
        //do stuff here
   return tax;
}

//Function invocation
var myTax=doTax(50000,2);

In the code above the function keyword is being used in the expression - we assign the anonymous function to the variable doTax. After this assignment just the text of the function is assigned to the variable doTax - the anonymous function is not being invoked just yet. It’s important to understand that even though the code of this anonymous function ends with return tax; actually, the tax calculation and return of its value is not happening until the doTax() is invoked. Only then the function is evaluated and the variable myTax will get whatever value this function returns.

Yet another example of a function expression is when it’s placed inside the grouping operator - parentheses as shown below:

(function calcTax (income, dependents){
   // Do stuff here
});

Another interesting concept of JavaScript is self-executing functions. Adding an extra pair of parentheses will cause the function expression located in the first set of parentheses to be executed right away.

(function calcTax (income, dependents){
   // Do stuff here
})();

The first set of parentheses hides its internal code from the outside world creating a scope or a closed ecosystem, where the function’s code will operate. Try to add a line invoking this function after the last line in the above code sample, e.g. calcTax(50000,2), and you’ll get an error - "calcTax is not defined". There is a way to expose some of the internal content of such a closure and you’ll see how to do it later in this chapter.

JavaScript Objects. Gentle Introduction

JavaScript objects are simply unordered collections of properties. You can assign new or delete existing properties from the objects during the runtime whenever you please. In classical object oriented languages there are classes and there are objects. For example, based on one Java a class you can create multiple instances of its objects.

Note
The ECMAScript 6 specification will include classes too, but since it’s a work in progress we won’t consider them as something useful in the today’s world. If you’d like to experiment with the upcoming features of JavaScript, download the Chrome Canary browser, go to chrome:flags and enable experimental JavaScript.

In JavaScript you can create objects using one of the following methods:

  • Using object literals

  • Using new Object() notation

  • Using Object.create()

  • Using constructor functions and a new operator.

Note
In JavaScript everything is an Object. Think of Object as of a root of of the hierarchy of all objects used in your program. All your custom objects are descendants from Object.

Object Literals

The easiest way to create a JavaScript object is by using the object literal notation. The code sample below starts with a creation of an empty object. The second line creates an object with one property salary and assigns the value of 50000 to it. Finally, the instance of one more object pis created and the variable person points at it.

var t = {}             // create an instance of an empty object

var a = {salary: 50000}; // an instance with one property

// Store the data about Julia Roberts
var person = { lastName: ”Roberts”,
               firstName: ”Julia”,
                     age: 42
             };

This object has three properties: lastName, firstName, and age. Note that in object literal notation the values of these properties are specify using colon. You can access the properties of this person using the dot notation, e.g. person.LastName. But JavaScript allows yet another way of accessing the object properties by using square bracket syntax, for example person["lastName"]. In the next code sample you’ll see that using the square brackets is the only way to access the property.

 var person = {
       "last name": "Roberts",
       firstName: "Julia",
             age: 42};

var herName=person.lastName;          // <1>

console.error("Hello " + herName);    // <2>

herName=person["last name"];           // <3>

person.salutation="Mrs. ";

console.log("Hello "+ person.salutation + person["last name"]); // <4>
  1. The object person doesn’t have a property lastName, but no error is thrown

  2. This will print "Hello undefined"

  3. Using and alternative way of referring to an object property

  4. This will print "Hello Mrs. Roberts"

Tip
It’s a good idea to keep handy a style guide of any programming language, and we know two of such documents for JavaScript. Google has published their version of JavaScript Style Guide at http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml. A more detailed Airbnb JavaScript Style Guide is available as a github project at https://github.com/airbnb/javascript.

Objects can contain other objects. If a property of an object literal is also an object, you just need to specify the value of this property in an extra pair of curly braces. For example, you can represent the telephone of a person as an object having two properties: the type and the number. The following code snippet adds a nested object to store a work phone as a nested object inside the person’s object. Run this code in the FireBug’s console and it’ll print "Call Julia at work 212-555-1212".

var p = { lastName: "Roberts",
                firstName: "Julia",
                age: 42,
                phone:{
                      type: "work",
                      numb: "212-555-1212"
                 }
            };
console.log("Call " + p.firstName + " at " + p.phone.type + " " + p.phone.numb );

What if a person has more then one phone? We can change the name of the property phone to phones and instead store an array of objects. JavaScript arrays are surrounded by square brackets, and they are zero based. The following code snippet will print "Call Julia at home 718-211-8987".

var p = { lastName: "Roberts",
                firstName: "Julia",
                age: 42,
                phones:[{
                      type: "work",
                      numb: "212-555-1212"
                 },
                 {
                      type: "home",
                      numb: "799-211-8987"

                 }]
            };
console.log("Call " + p.firstName + " at " + p.phones[1].type + " " + p.phones[1].numb );
Methods in Object Literals

Functions defined inside objects are called methods. Defining methods in object literals is similar to defining properties - provide a method name followed by a colon and the function declaration. The code snippet below declares a method makeAppoyntment() to our object literal. Finally, the line p.makeAppointment(); invokes this new method, which will print the message on the console that Steven wants to see Julia and will call at so-and-so number.

var p = { lastName: "Roberts",
                firstName: "Julia",
                age: 42,
                phones:[{
                      type: "work",
                      numb: "212-555-1212"
                 },
                 {
                      type: "home",
                      numb: "718-211-8987"

                 }],
                makeAppointment: function(){
                    console.log("Steven wants to see  " + this.firstName +
                                 ". He'll call at " + this.phones[0].numb);
                }
            };

p.makeAppointment();
Note
Since we already started using arrays, it’s worth mentioning that arrays can store any objects. You don’t have to declare the size of the array upfront and can create new arrays as easy as var myArray=[] or var myArray=new Array(). You can even store function declarations as regular strings, but they will be evaluated on the array initialization. For example, during the greetArray initialization the user will see a prompt asking to enter her name, and, when it’s done, the greetArray will store two strings. The output of the code fragment below can look like "Hello, Mary".
var greetArray=[
    "Hello",
    prompt("Enter your name", ”Type your name here")
];

console.log(greetArray.join(","));

We’ve briefly covered object literals, and you to start using them. In Chapter 4 you’ll be learning about JSON - a popular data format used as replacement for XML in the JavaScript world. Then you’ll see how similar are the syntax of JSON and JavaScript object literals. Now we’ll spend a little bit of time delving into JavaScript functions, and then - back to objects again.

Constructor Functions

JavaScript functions are more then just some named pieces of code that implements certain behavior. They also can become objects themselves by a magic of the new operator. To make things even more intriguing, the function calls can have memories, which will be explained in the section about closures.

If a function is meant to be instantiated with the new operator it’s called a constructor function. If you are familiar with Java or C# you understand the concept of a class constructor that is being executed only once during the instantiation of a class. Now imagine that there is only a constructor without any class declaration that still can be instantiated with the new operator as in the following example.


function Person(lname, fname, age){
         this.lastName=lname;
         this.firstName=fname;
         this.age=age;
};

// Creating 2 instances of Person
var p1 = new Person(“Roberts”,“Julia”, 42);

var p2 = new Person(“Smith”, “Steven”, 34);

This code declares the function Person and after that, it creates two instances of the Person objects referred by the variables p1 and p2 accordingly. This is what the statement functions are objects means.

Note
According to common naming conventions the names of the constructor functions are capitalized.

Objects can have methods and properties, right? On the other hand, functions are objects. Hence functions can have methods and properties too. If you declare a function marryMe() inside the constructor function Person, marryMe() becomes a method of Person. This is exactly what we’ll do next. But this time we’ll create an HTML file that includes the <script> section referring to the JavaScript code sample located in a separate file.

If you want to try it hands-on, create a new file in your Aptana project by selecting the menu File | New | File and give it a name marryme.js. Agree with a suggested default JavaScript template, and key in the following content into this file:


function Person(lname, fname, age){
         this.lastName=lname;
         this.firstName=fname;
         this.age=age;

         this.marryMe=function(person){
                console.log("Will you marry me, " + person.firstName);
         };

};

var p1= new Person("Smith", "Steven");
var p2= new Person("Roberts", "Julia");

p1.marryMe(p2);

The code above uses the keyword this that refers to the object (a.k.a. context) where the code will execute. If you are familiar with the meaning of this in Java or C#, it’s similar, but not exactly the same, and we’ll illustrate it in the section titled "Who’s this". The method marryMe() of one Person object takes an instance of another Person object and makes an interesting proposition: "Will you marry me, Julia".

This time we won’t run this code in the Firebug’s console, but rather will include it in the HTML file. In Aptana, create a new File | New | File, enter marryme.html as the file name and press the button Finish. Don’t press the button Next as it’ll offer you to select from one of the HTML templates, but this would generate lots of HTML content, which is not needed for our code sample. Just type in the following in the newly created empty file marryme.html.

<!DOCTYPE html>
<html>
        <head>
                <meta charset="utf-8" />
        </head>

        <body>
                <h1>Making Proposal</h1>

                <script src="marryme.js"></script>
        </body>
</html>

Debugging JavaScript in Firebug

In Aptana, right-click on the file marryme.html and select the option Run As | JavaScript Web Application. We continue using Firefox as Aptana’s default browser, and you’ll see it open a new Web page that reads "Making Proposals". Open the Firebug using the View menu, refresh the page and switch to the Firebug’s tab Script. You’ll see the split panel with the JavaScript code from marryme.js on the left.

image

Figure 2-8. Firebug’s Script panel

Let’s set a breakpoint inside the method marryMe() by clicking in the Firebug’s gray area to the left of the line 7. You’ll see a red circle that will reveal a yellow triangle as soon as your code execution will hit this line. Refresh the content of the browser to re-run the script with a breakpoint. Now the execution stopped at line 7, the right panel contains the runtime information about the objects and variables used by your program.

fig_02_09.jpg

Figure 2-9. Firebug’s Script panel at a breakpoint

On the top of the left panel you’ll see usual for debuggers curved arrows (Step Into, Step Over, Step Out) as well as triangular button to continue code execution. The right panel depicts the information related to this and global Window objects. In Figure 2-9 this represents the instance of the Person object represented by the variable p1 (Steven Smith). To see the content of the object, received by the method marryMe() you can add the watch variable by clicking on the text "New watch expression…" and entering person - the name of the parameter of marryMe(). Figure 2-10 shows the watch variable person (Julia Roberts) that was used during the invocation of the method marryMe().

image

Figure 2-10. Firebug’s Script panel at a breakpoint

Now click on the Firebug’s Net panel, which shows what goes over the network during communication between the Web browser and Web server. Figure 2-11 shows a screen shot of the Net panel where we clicked on the Headers tab for marryme.html and the Response tab of marryme.js. The code 200 for both files means that they arrived successfully to the browser. It also shows the IP address of the Web server they came from, their sizes, and plenty of other useful information. Both Script and Net panels of Firebug or any other developers tools are your best friends of any Web developer.

image

Figure 2-11. Firebug’s Net panel

We like Firebug, but testing and debugging should be done in several Web browsers. Besides Firebug, we’ll be using excellent Google Chrome developers tools. Their menus and panels are similar and we won’t be including such mini-tutorials on using such tools - you can easily learn them on your own.

Notes on Arrays

A JavaScript array is a grab bag of any objects. You don’t have to specify in advance the number of elements to store, and there is more than one way to create and initialize array instances. The following code samples are self-explanatory.


var myArray=[];
    myArray[0]="Mary";
    myArray[2]="John";

// prints undefined John
console.log(myArray[1] + " " + myArray[2]);

var states1 = ["NJ", "NY", "CT", "FL"];

var states = new Array(4);  // size is optional

states[0]="NJ";

states[1]="NY";

states[2]="CT";

states[3]="FL";

// remove one array element
delete states[1];


// prints undefined CT length=4
console.log(states[1] + " " + states[2] + " Array length=" + states.length);

// remove one element starting from index 2
states.splice(2,1);

// prints undefined  FL length=3
console.log(states[1] + " " + states[2] + " Array length=" + states.length);

Removing elements with delete creates gaps in the arrays while using the array’s method splice() allows to remove or replace the specified range of elements closing gaps.

The next code sample illustrates an interesting use case when we assign a string and a function text as array elements to mixedArray. During array initialization the function promt() will be invoked, the user will be prompted to enter name, and after that, two strings will be store in mixedArray, for example "Hello" and "Mary".


var mixedArray=[
    "Hello",
    prompt("Enter your name", ”Type your name here")
];

Prototypal Inheritance

JavaScript doesn’t support classes, at least till the ECMAScript 6 will become a reality. But JavaScript allows you to create objects that inherit properties and methods of other objects. By default, all JavaScript objects are inherited from Object. Each JavaScript construction function has a special property called prototype, which points at this object’s ancestor. If you want to create an inheritance chain where an instances of constructor function ObjectB extend ObjectA just write one line of code: ObjectB.prototype=ObjectA;.

image

Figure 2-12. Prototypal Inheritance

Consider two constructor functions Employee and Person shown in the code snippet below.They represent two unrelated objects. But assigning the Person object to the prototype property of Employee creates an inheritance chain, and now the object emp will have all properties defined in both Employee and Person.


function Person(name, title){
        this.name=name;
        this.title=title;
        this.subordinates=[];
}

function Employee(name, title){
        this.name=name;
        this.title=title;
}

// All instances of Employee will extend Person
Employee.prototype = new Person();            // <1>

var emp=new Employee("Mary", "Specialist"); // <2>

console.log(emp);      // <3>
  1. Assigning an ancestor of type person

  2. Instantiating Employee

  3. Printing the object referred by emp will output [object Object]. It happens because each object has a method toString(), and if you want it to output useful information - override it. You’ll see how to do it later in this section.

We want to stress, that the property prototype exists on constructor functions. After creating specific instances of such objects you may see that these instances have another property called proto. At the time of this writing this property is not a standard yet and won’t be supported in some older browsers, bit ECMAScript 6 will make it official. To illustrate the difference between prototype and proto let’s add the following piece of code to the above sample:


//Create an instance of Person and add property dependents
var p=new Person();
p.dependents=1;                                 // <1>


var emp2=new Employee("Joe", "Father");

//This employee will have property dependents

emp2.__proto__=p;                               // <2>

console.log("The number of Employee's dependents " + emp2.dependents); // <3>
  1. Creating an instance of Person and adding an extra property dependents just for this instance

  2. Assigning this instance to the __proto__ property of one instance

  3. The code will properly print 1 as a number of dependents of the Employee instance represented by the variable emp2. The variable emp from the previous code snippet won’t have the property dependents.

To try it hands-on, open the file WhoIsYourDaddy.html in Aptana. Just for a change, this time we’ll use Google Chrome Developer Tools by opening the menu View | Developer | Developer Tools. Set the breakpoint at the last line of the JavaScript, refresh the Web page content, and add the watch expressions for the variables p, emp, and emp2. When the JavaScript code engine runs into emp2.dependents it tries to find this property in property on the Employee object. If not found, the engine checks all the objects in the prototypal chain (in our case it’ll find it in the object p) all the way up to the Object if need be.

Tip
If you need to do some programmatic manipulations with only those properties that are defined on the specific object (not in its ancestors) do the check with the method hasOwnProperty().

image

Figure 2-13. The instance-specific __proto__ variable

Tip
You can find a tutorial on using Google Chrome Developer Tools at https://developers.google.com/chrome-developer-tools/.

Please not the difference in the content of the variables __proto__ of the instances represented by emp and emp2. These two employees are inherited from two differnet objects Person. Isn’t it scary? Not really.

Where to Declare Methods

If you take a closer look at the screenshot from Figure 2-13 you’ll see that the Person and Employee objects have redundant properties name and title. We’ll deal with this redundancy in the section titled "Call and Apply". But first let’s introduce and cure the redundancy in method declarations when the prototypal inheritance is used.

Let’s add a method to addSubordinate() to the ancestor object Person that will populate its array subordinates. Who knows, maybe an object Contractor (descendant of a Person) will need to be added in the future, so the ancestor’s method addSubordinate() can be reused. First, we’ll do it the wrong way to illustrate the redundancy problem, and then we’ll do it right. Consider the following code:

// Constructor function Person
function Person(name, title){
        this.name=name;
        this.title=title;
        this.subordinates=[];

    // Declaring method inside the constructor function
        this.addSubordinate=function (person){
                this.subordinates.push(person)
        }


}

// Constructor function Employee
function Employee(name, title){
        this.name=name;
        this.title=title;
}

// Changing the inheritance of Employee
Employee.prototype = new Person();

var mgr =  new Person("Alex", "Director");
var emp1 = new Employee("Mary", "Specialist");
var emp2 = new Employee("Joe", "VP");

mgr.addSubordinate(emp1);
mgr.addSubordinate(emp2);
console.log("mgr.subordinates.length is " + mgr.subordinates.length);

The method addSubordinate() here is declared inside the constructor function Person, which becomes an ancestor of the Employee. After instantiation of two Employee objects the method addSubordinate() is duplicated for each instance.

Let’s use Google Chrome Developer Tools profiler to see the sizes of the objects allocated on the Heap memory. But first we’ll set up two breakpoints - one before, and one after creating our instances as shown on Figure 2-14.

image

Figure 2-14. Preparing Breakpoints Take 1.

When the execution of the code will stop at the first breakpoint, we’ll switch to the Profiler tab and take the first Heap snapshot. Upon reaching the second breakpoint we’ll take another Heap snapshot. The dropdown at the status bar allows to view the objects allocated between the snapshots 1 and 2. Figure 2-15 depicts this view of the profiler. Note that the total size (the Shallow Size column) for the Person instances is 132 bytes. Employee instances weigh 104 bytes.

image

Figure 2-15. Objects allocated between snapshots 1 and 2

Now we’ll change the code to declare the method not inside the Person constructor function, but on it’s prototype - and this is the right way to declare methods in functions to avoid code duplication.

// Constructor function Person
function Person(name, title){
        this.name=name;
        this.title=title;
        this.subordinates=[];

}

//Declaring method on the object prototype
Person.prototype.addSubordinate=function(){
   var subordinate=new Employee(this.name, this.title);
   this.subordinates.push(subordinate);
   return subordinate;
}

// Constructor function Employee
function Employee(name, title){
        this.name=name;
        this.title=title;
}

// Changing the inheritance of Employee
Employee.prototype = new Person();

var mgr =  new Person("Alex", "Director");
var emp1 = new Employee("Mary", "Specialist");
var emp2 = new Employee("Joe", "VP");

mgr.addSubordinate(emp1);
mgr.addSubordinate(emp2);
console.log("mgr.subordinates.length is " + mgr.subordinates.length);

Similarly, we’ll set up two breakpoints before and after object instantiation as shown in Figure 2-16.

image

Figure 2-16. Preparing Breakpoints Take 2.

Let’s take two more profiler snapshots: one upon reaching the first breakpoint, and another one upun reaching the second. While the weight of the Employee instances remained the same (104 bytes), the Person instances became lighter: 112 bytes. While 20 bytes may not seem like a big deal, if you’ll need to create hundreds or thousands of object instances it adds up.

image

Figure 2-17. Objects allocated between snapshots 3 and 4

So if you need to declare a method on the object that will play a role of the ancestor, do it on the prototype level. The only exception to this rule is the case when such method needs to use some object specific variable that’s different for each instance - in case declare methods inside the constructors (see the section on closures for details).

Note
All modern Web browsers support the function Object.create(), which creates a new object based on another prototype object. For example, var objectB=Object.create(objectA);. What if you must support an older browser and need such "create by example" functionality? Of course, you can always create a custom arbitrarily named function with the similar functionality as the latest implementation of Object.create(). But the future-proof approach is to create the missing methods with the same signatures and on the same objects as the latest ECMAScript specification prescribes. In case of Object.create() you can use the implementation offered by Douglas Crockford:
if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}
newObject = Object.create(oldObject);

Such approach of custom implementation of missing pieces according to the latest ECMAScript specifications is known as polyfills. People who can’t wait till the browser vendors will implement the newest functionality create cross-browser polyfills and some of them submit their source code to the public domain. You can find a number of polyfills in the git repository of the Modernizr project.

Method overriding

Since JavaScript allows declaring methods on an object as well as on its prototype, overriding a method becomes really simple. The following code sample declares the method addSubordinate() on the prototype of the Person object, but then the object p1 overrides this method.

function Person(name, title){

  this.name=name;
  this.title=title;
  this.subordinates=[];
}

Person.prototype.addSubordinate=function(person){

   this.subordinates.push(person);
   console.log("I'm in addSubordinate on prototype " + this);
}

var p1=new Person("Joe", "President");

    p1.addSubordinate=function(person){

    this.subordinates.push(person);
    console.log("I'm in addSubordinate in object " + this);
  }

var p2 = new Person("Mary", "Manager")

    p1.addSubordinate(p2);

Running the above code prints only one line: "I’m in addSubordinate in object [object Object]". This proves that the method addSubordinate() on the prototype level is overridden. We can also improve this example a little bit and override the method toString() on the Person. Just add the following fragment to the prior to instantiating p1.

Person.prototype.toString=function(){
   return "name:" + this.name +" title:" + this.title;
}

Now the code prints "I’m in addSubordinate in object name:Joe, title:President". Overriding the method toString on objects is a common practice as it gives a textual representation of your objects.

Scope or who’s this?

You are about to read one of the most confusing sections in this book. The confusion is caused by some inconsistencies in JavaScript design and implementations be various browsers. Do you know what will happen if you’ll remove the keywords this from the toString() method from previous section? You’ll get an error - the variable title is not defined. Without the keyword this the JavaScript engine tries to find the variable title in the global namespace. Declaring and initializing the variable title outside of the Person declaration get rid of this error, but this is not what we want to do. Misunderstanding of the current scope can lead to difficult to debug errors.

Caution
Interestingly enough replacing this.name with name doesn’t generate an error, but rather initializes the variable name with an empty string. Although name is not an officially reserved JavaScript keyword, there are articles in the blogosphere that don’t recommend using the word name as a variable name. Keep this list handy to avoid running into an unpredictable behavior.

Let’s consider several examples that will illustrate the meaning of this variable in JavaScript. The code sample below defines an object myTaxObject and calls its method doTaxes(). Notice two variables with the same name taxDeduction - one of them has global scope and another belongs to myTaxObject. This little program was written for mafia and will apply some under the table deduction for the people who belong to Cosa Nostra.

var taxDeduction=300;      // global variable

var myTaxObject = {

    taxDeduction: 400,    // object property

    doTaxes: function() {
         this.taxDeduction += 100;

         var mafiaSpecial= function(){
           console.log( "Will deduct " + this.taxDeduction);
         }

         mafiaSpecial();  // invoking as a function
    }
}

myTaxObject.doTaxes();  //invoking method doTaxes

This code fragment illustrates the use of nested functions. The object method doTaxes() has a nested function mafiaSpecial(), which is not visible from outside of the myTaxObject, but it can be certainly invoked inside doTaxes(). What number do you think this code will print after the words "Will deduct "? Will it print three, four, or five hundred? Run this code in Firebug, Chrome Developer Tools or any other way and you’ll see that it’ll print 300!

But this doesn’t sound right, does it? The problem is that in JavaScript the context where the function executes depends on the way it was invoked. In this case the function mafiaSpecial() was not invoked as a function (not a method) without specifying the object it should apply to, and JavaScript makes it operate in the global object, hence the global variable taxDeduction having the value of 300 is being used. So in expression this.taxDeduction the variable this means global unless the code is operated in the strict mode.

Note
ECMAScript 5 introduced a restricted version of JavaScript called strict mode, which among other things places stricter requirements to variable declarations and scope identification. Adding "use strict" as the first statement of the method doTax() will make the context undefined, and it’ll print the error "this is undefined" and not 300. You can read about the stict mode at Mozilla’s developers site.

Let’s make a slight change to this example and take to control what this represents. When the object myTaxObject was instantiated its own this reference was created. The following code fragment stores this reference in additional variable thisOfMyTaxObject changes the game and the expression thisOfMyTaxObject.taxDeduction evaluates to 500.

var taxDeduction=300;      // global variable

var myTaxObject = {

    taxDeduction: 400,    // object property

    doTaxes: function() {
    var thisOfMyTaxObject=this;
         this.taxDeduction += 100;

         var mafiaSpecial= function(){
           console.log( "Will deduct " + thisOfMyTaxObject.taxDeduction);
         }

         mafiaSpecial();  // invoking as a function
    }
}

myTaxObject.doTaxes();  //invoking method doTaxes

You’ll see a different way of running a function in the context of the specified object using special functions call() and apply(). But for now consider one more attempt to invoke mafiaSpecial()`shown in the following example that uses `this.mafiaSpecial() notation.

var taxDeduction=300;      // global variable

var myTaxObject = {

    taxDeduction: 400,    // object property

    doTaxes: function() {
         this.taxDeduction += 100;

         var mafiaSpecial= function(){
           console.log( "Will deduct " + this.taxDeduction);
         }

         this.mafiaSpecial();  // trying to apply object's scope
    }
}

myTaxObject.doTaxes();  //invoking method doTaxes

Run the above code and it’ll give you the error "TypeError: this.mafiaSpecial is not a function" and rightly so. Take a closer look at the object myTaxObject represented by the variable this. The myTaxObject has only two properties: taxDeduction and doTaxes. The function mafiaSpecial is hidden inside the method doTaxes and can’t be accessed via this.

Call and Apply

Visualize the International Space Station, and add to the picture an image of a approaching space shuttle. After attaching to the docking bay of the station the shuttle’s crew performs some functions on the station (a.k.a. object) and then flies to another object or back to Earth. What is has to do with JavaScript? It can serve as an analogy for creating a JavaScript function that can operate in the scope of any arbitrary object. For this purpose JavaScript offers two special functions: call() or apply(). Both call() and apply() can invoke any function on any object. The only difference between them is that apply() passes required parameters to a function as an array, while call() uses a comma-separated list.

Tip
Every function in JavaScript is a Function object. Both call() and apply() are defined in the Function object.

For example, a function calcStudentDeduction(income,numOfStudents) can be invoked in a context of a given object using either call() or apply(). Note that with call() parameters have to be listed explicitly, while with apply parameters are given as an array:

calcStudentDeduction.call(myTaxObject, 50000, 2);

calcStudentDeduction.apply(myTaxObject, [50000, 2]);

In the above example the instance of ‘myTaxObject` can be referred as this from within the function calcStudentDeduction() even though this is a function and not a method. The last example from the previous section can be re-written to invoke mafiaSpecial(). The following code will ensure that mafiaSpecial() has this pointing to `myTaxObject’ and will print on the console "Will deduct 500".

var taxDeduction=300;      // global variable

var myTaxObject = {

    taxDeduction: 400,

    doTaxes: function() {
         this.taxDeduction += 100;

         var mafiaSpecial= function(){
           console.log( "Will deduct " + this.taxDeduction);
         }

         mafiaSpecial.call(this);  // passing context to a function
    }
}

myTaxObject.doTaxes();

Callbacks

Can you live without using call() and apply()? Sure you can, but in JavaScript can easily create callbacks - you can pass the code of one function as a parameter to another function for execution in the latter function’s context. Most likely you’ve seen how event handlers are declared. If a user clicks on this button here’s the name of the handler function to call: myButton.addEventListener("click", myFunctionHandler)

It’s important to understand that you don’t not immediately call the function myFunctionHandler here - you are just registering it. If and only if the user will click on myButton then the callback myFunctionHandler has to be invoked in the context of the myButton object. The functions call() and apply() exist exactly for this purpose.

Let’s consider an example when you need to write a function that will take two arguments - and array with preliminary tax data and a callback function to be applied to each element of this array. The following code sample creates myTaxObject that has two properties: taxDeduction and the applyDeduction. The latter is a method with two parameters: array and a callback to be applied to this array.

var myTaxObject = {

    taxDeduction: 400,

    // this function takes an array and callback as params
    applyDeduction: function(someArray, someCallBackFunction){

        for (var i = 0; i < someArray.length; i++){

            // Invoke the callback
           someCallBackFunction.call(this, someArray[i]);
        }

    }
}

// array
var preliminaryTaxes=[1000, 2000, 3000];

// tax handler function
var taxHandler=function(currentTax){
                   console.log("Hello from callback. Your final tax is " +
                   (currentTax - this.taxDeduction));
                }

// invoking applyDeduction passing an array and callback
myTaxObject.applyDeduction(preliminaryTaxes, taxHandler);

The above code invokes applyDeduction() passing it the array preliminaryTaxes and the callback function taxHandler that takes the currentTax and subtracts this.taxDeduction. By the time this callback will be applied to each element of the array the value of this will be known and this code will print the following:

Hello from callback. Your final tax is 600
Hello from callback. Your final tax is 1600
Hello from callback. Your final tax is 2600

You may be wondering, why passing the function to another object if we could take an array, subtract 400 from each of its elements and be done with it? The solution with callbacks gives you an ability to make the decision on what function to call during the runtime and call it only when a certain event happens. Callbacks allow you to do asynchronous processing. For example, you make an asynchronous request to a server and register the callback to be invoked if a result comes back. The code is not blocked and doesn’t wait until the server response is ready. Here’s an example from AJAX: request.onreadystatechange=myHandler. You register myHandler callback but not immediately call it. JavaScript functions are objects, so get used to the fact that you can pass them around as you’d be passing any objects.

Hoisting

A variable scope depends on where it was declared. You already had a chance to see that a variable declared inside a function with the keyword var is visible only inside this function. Some programming languages allow to narrow down the scope even further. For example, in Java declaring a variable inside any block of code surrounded with curly braces makes it visible only inside such a block. In JavaScript it works differently. No matter where in the function you declared the variable its declaration will be hoisted to the top of the function, and you can use this variable anywhere inside the function.

The following code snippet will print 5 even though the variable b has been declared inside the if-statement. It’s declaration has been hoisted to the top:

function test () {
    var a=1;

    if(a>0) {
        var b = 5;
    }
    console.log(b);

}

test();

Let’s make a slight change to the above code to separate the variable declaration and initialization. The following code has to console.log(b) statements. The first one will output undefined and the second will print 5 just as in the previous example.

function test () {
    var a=1;

    console.log(b);  // b is visible, but not initialized

    if(a>0) {
        var b;
    }

    b=5;

    console.log(b);  // b is visible and initialized
}

test();

Due to hoisting, JavaScript doesn’t complain when the first console.log(b) is invoked. It knows about the variable b, but its value is undefined just yet. By the time the second console.log(b) is called, the variable b was initialized with the value of 5. Just remember that hoisting just applies to variable declaration and doesn’t interferes with your code when it comes to initialization. JavaScript function declarations are hoisted too, and this is illustrated in the following code sample.

function test () {
    var a=1;

    if(a>0) {
        var b;
    }

    b=5;

    printB();

    function printB(){
        console.log(b);
    }
}

test();

This code will print 5. We can call the function printB() here because its declaration was hoisted to the top. But the situation changes if instead of function declaration we’ll use the function expression. The following code will give you an error "PrintB is not a function". Notice that it the error doesn’t complain about printB being undefined cause the variable declaration was hoisted, but since the function expression wasn’t the JavaScript engine doesn’t know yet that printB will become a function really soon. Anyway, moving the invocation line printB() to the bottom of the function test() cures this issue. Function expressions are not being hoisted.

function test () {
    var a=1;

    if(a>0) {
        var b;
    }

    b=5;

    printB();

    var printB = function(){
        console.log(b);
    }

}

test();

All code samples in this section first declare the function test() and then invoke it. This function test() is being called once and there is no reason to give it a name. Using so called self-invoked function notation allows to declare and automatically invoke the function (note the extra parentheses at the end of the following code).

(function () {
    var a=1;

    if(a>0) {
        var b;
    }

    b=5;

    printB();

    var printB = function(){
        console.log(b);
    }

})();

Function properties

Functions as any other objects can have properties. You can attach any properties to a Function object and their values can be used by all instances of this object. Static variables in programming languages with the classical inheritance is the closest analogy to function properties in JavaScript.

Let’s consider an example of a constructor function Tax. An accounting program can create multiple instances if Tax - one per person. Say this program will be used in a Florida neighborhood with predominantly Spanish speaking people. The following code illustrates the case when the method doTax() can be called with or without parameters.

function Tax(income, dependents){
    this.income=income;              // instance variable
    this.dependents=dependents;      // instance variable

    this.doTax = function calcTax(state, language){
           if(!(state && language)){     // <1>
              console.log("Income: " + this.income + " Dependents: "+ this.dependents
              + " State: " + Tax.defaults.state + " language:" + Tax.defaults.language);
           } else{                       // <2>
              console.log("Income: " + this.income + " Dependents: "+ this.dependents
              + " State: " + state + " language:" + language);
           }
    }
}

Tax.defaults={                           // <3>
     state:"FL",
     language:"Spanish"
};

// Creating 2 Tax objects
var t1 = new Tax(50000, 3);
    t1.doTax();                          // <4>
var t2 = new Tax(68000, 1);
    t2.doTax("NY","English");            // <5>
  1. No state and language were given to the method doTax()

  2. The state and language were provided as doTax() parameters

  3. Assigning the object with two properties as a defaults property on Tax. The property default is not instance specific, which makes it static.

  4. Invoking doTax() without parameters - use defaults

  5. Invoking doTax() with parameters

This program will produce the following output:

Income: 50000 Dependents: 3 State: FL language:Spanish
Income: 68000 Dependents: 1 State: NY language:English

You can ass as many properties to the function as needed. For example, to count the number of instances of the Tax object just add one more property Tax.counter=0;. Now add to the Tax function something like console.log(Tax.counter++); and you’ll see that the counter increments on each instance creation.

Tip
If multiple instances of a function object need to access certain HTML elements of the DOM, add references to these elements as function properties so objects can reuse them instead of traversing the DOM (it’s slow) from each instance.

Closures

TODO

Mixins

TODO

JavaScript and HTML Elements

After learning all these facts and techniques about the language you might be eager to see "the real use of JavaScript" – manipulating HTML elements of Web pages, which most of the people use JavaScript for. This is correct, at least today. In this section we’ll be doing exactly this – applying JavaScript code to HTML elements.

First let’s consider the operations your application needs to be able to perform inside the Web page:

  • Programmatically finding the required element by id, type, or a CSS class.

  • Changing styles of the elements (show, hide, apply fonts and colors et al.)

  • Processing events that may happen to HTML elements (click, mouseover et al.)

  • Dynamically adding or removing HTML elements from the page or changing their contents

  • Communicating with the server side, e.g. form submission or making AJAX requests for some data from the server

You need to understand how to perform these operations from JavaScript. Even if you’ll be using one of the popular frameworks, you’ll be performing the same operations applying the syntax prescribed by your framework of choice. So let’s get started.

Styling Web Pages with CSS

CSS stands for Cascading Style Sheets. During the last 15 years several CSS specifications reached the level of Recommendation by W3C: CSS Level 1, 2, and 2.1. The latest CSS Level 3 (a.k.a. CSS3) adds new features to CSS 2.1 module by module, which are listed at http://www.w3.org/Style/CSS/current-work.

Tip
You can find CSS tutorial as well as tons of other learning resources at webplatform.org/.

You can include CSS into a Web page either by linking to separate files using the HTML tag <link> or by in-lining the styles with the tag <style>. For example, if CSS is located in the file mystyles.css in the folder css add the following tag to HTML:

<link rel="stylesheet" type="text/css" href="css/mystyles.css" media="all">

The <link> tag allows specifying the media where specific css file has to be used. For example, you can have one CSS file for smartphones and another one for tablets. We’ll discuss this in detail in the section on media queries in Chapter 11.

You should put this tag in the section of your HTML before any JavaScript code to make sure that they stiles are loaded before the content of the Web page.

Placing the @import attribute inside the <style> tag allows to include styles located elsewhere:

<style>
   @import url (css/contactus.css)
</style>

What’s the best way of including CSS in HTML? From one hand, keeping CSS in multiple files separately form HTML and JavaScript makes the code more readable and reusable. On the other hand, when if your Web site has consists of many files, the Web browser will have to make multiple round trips to your server just to load the page, which can slow down the responsiveness of your Web application.